1 module hip.hipaudio.backend.openal.player;
2 version(OpenAL):
3 import hip.hipaudio.backend.openal.clip;
4 import hip.hipaudio.backend.openal.source;
5 import hip.hipaudio.backend.openal.al_err;
6 import hip.hipaudio.audio;
7 import hip.error.handler;
8 import hip.audio_decoding.audio;
9 import hip.math.vector;
10 import bindbc.openal;
11 
12 
13 package ALenum getFormatAsOpenAL(AudioConfig cfg)
14 {
15     if(cfg.channels == 1)
16     {
17         if(cfg.format == AudioFormat.float32Big || cfg.format == AudioFormat.float32Little)
18             return AL_FORMAT_MONO_FLOAT32;
19         else if(cfg.format == AudioFormat.signed16Little || cfg.format == AudioFormat.signed16Big)
20             return AL_FORMAT_MONO16;
21         else
22             return AL_FORMAT_MONO8;
23     }
24     else
25     {
26         if(cfg.format == AudioFormat.float32Big || cfg.format == AudioFormat.float32Little)
27             return AL_FORMAT_STEREO_FLOAT32;
28         else if(cfg.format == AudioFormat.signed16Little || cfg.format == AudioFormat.signed16Big)
29             return AL_FORMAT_STEREO16;
30         else
31             return AL_FORMAT_STEREO8;
32     }
33 }
34 
35 
36 
37 /**
38 * Wraps OpenAL API onto the IAudioPlayer interface. With that, when HipAudioSourceAPI receives that interface,
39 * it will update OpenAL properties through that interface.
40 */
41 public class HipOpenALAudioPlayer : IHipAudioPlayer
42 {
43     public this(AudioConfig cfg)
44     {
45         initializeOpenAL();
46         config = cfg;
47     }
48     public static bool initializeOpenAL()
49     {
50         ErrorHandler.startListeningForErrors("HipremeAudio3D initialization");
51         version(BindOpenAL_Static){}
52         else
53         {
54             ALSupport sup = loadOpenAL();
55             if(sup != ALSupport.al11) //Probably should not load a non al11 version.
56             {
57                 if(sup == ALSupport.badLibrary)
58                     ErrorHandler.showErrorMessage("Bad OpenAL Support", "Unknown version of OpenAL");
59                 else
60                 {
61                     ErrorHandler.showErrorMessage("OpenAL not found", "Could not find OpenAL library");
62                     return false;
63                 }
64             }
65         }
66         device = alcOpenDevice(alcGetString(null, ALC_DEVICE_SPECIFIER));
67         if(device == null)
68         {
69             ErrorHandler.showErrorMessage("OpenAL Initialization", "Error on creating device");
70             return false;
71         }
72         //static const ALCint* contextAttr = [ALC_FREQUENCY, 22_050, 0];
73         context = alcCreateContext(device, null);
74         if(context == null)
75         {
76             ErrorHandler.showErrorMessage("OpenAL context error", "Error creating OpenAL context");
77             return false;
78         }
79         if(!alcMakeContextCurrent(context))
80 		    ErrorHandler.showErrorMessage("OpenAL context error", "Error setting context");
81 
82         //Set Listener
83 
84         alListener3f(AL_POSITION, 0f, 0f, 0f);
85         alListener3f(AL_VELOCITY, 0f, 0f, 0f);
86 
87         version(BindOpenAL_Static)
88         {
89             if(&alEffecti is null)
90                 ErrorHandler.showErrorMessage("OpenAL EFX Error", "Could not load OpenAL EFX");
91         }
92         else
93         {
94             if(!alEffecti)
95                 ErrorHandler.showErrorMessage("OpenAL EFX Error", "Could not load OpenAL EFX");
96         }
97 
98         return ErrorHandler.stopListeningForErrors();
99     }
100     public AHipAudioSource getSource(bool isStreamed = false){return  new HipOpenALAudioSource(isStreamed);}
101 
102     public bool play_streamed(AHipAudioSource src)
103     {
104         HipOpenALAudioSource source = cast(HipOpenALAudioSource)src;
105         HipOpenALClip _buf = cast(HipOpenALClip)source.clip;
106         if(_buf.hasBuffer)
107         {
108             alSourcePlay(source.id);
109             alCheckError("Error querying OpenAL play streamed");
110             return true;
111         }
112         return false;
113     }
114     
115     public HipAudioClipAPI getClip(){return new HipOpenALClip(new HipAudioDecoder(), getClipHint());}
116     
117     public HipAudioClipAPI loadStreamed(string path, uint chunkSize)
118     {
119         HipAudioClipAPI clip = new HipOpenALClip(new HipAudioDecoder(), getClipHint(), chunkSize);
120         // clip.loadStreamed(path, getEncodingFromName(path));
121         return clip;
122     }
123 
124     public void updateStream(AHipAudioSource source)
125     {
126         // HipOpenALAudioSource src = cast(HipOpenALAudioSource)source;
127         // HipOpenALClip clip = cast(HipOpenALClip)src.buffer;
128         // ALuint b = clip.getALBuffer();
129         // alSourceQueueBuffers(src.id, 1, &b);
130         // alCheckError("Error enqueueing OpenAL buffer on source"));
131     }
132 
133 
134     //End Effects
135     public void onDestroy()
136     {
137         alcDestroyContext(context);
138         alcCloseDevice(device);
139         context = null;
140         device = null;               
141     }
142 
143     public void update()
144     {
145         
146     }
147 
148     /**
149     *   OpenAL has an embedded resampler
150     */
151     protected static HipAudioClipHint getClipHint()
152     {
153         HipAudioClipHint hint = {
154             outputChannels: HipOpenALAudioPlayer.config.channels,
155             outputSamplerate: HipOpenALAudioPlayer.config.sampleRate,
156             needsResample: false,
157             needsDecode: true
158         };
159         return hint;
160     }
161 
162     package __gshared AudioConfig config;
163     protected __gshared ALCdevice* device;
164     protected __gshared ALCcontext* context;
165 
166     /**
167     * Constant used for making the panning distance offset from the listener
168     */
169     public __gshared ALfloat PANNING_CONSTANT = 1000;
170 }